package me.zingon.webmvc.servlet;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import me.zingon.core.context.annotation.SRequestBody;
import me.zingon.core.context.annotation.SRequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Map;

public class SummerHandler {

    private static final String CONTENT_JSON = "application/json";

    Object controller;

    Method method;

    Parameter[] param;

    public SummerHandler(Object controller, Method method) {
        this.controller = controller;
        this.method = method;
        this.param = method.getParameters();
    }


    public Object handle(HttpServletRequest req, HttpServletResponse resp) {


        try {
            return method.invoke(controller, getParam(req, resp));
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return null;
    }

    private Object[] getParam(HttpServletRequest request, HttpServletResponse response) {
        Object[] result = new Object[param.length];
        Map<String, String[]> reqParam = request.getParameterMap();
        JSONObject requestPayload = null;
        if (request.getContentType()!=null && request.getContentType().equals(CONTENT_JSON)) {
            requestPayload = JSON.parseObject(getRequestPayload(request));
        }
        for (int i = param.length - 1; i >= 0; i--) {
            if (param[i].getType().equals(HttpServletRequest.class)) {
                result[i] = request;
                continue;
            }
            if (param[i].getType().equals(HttpServletResponse.class)) {
                result[i] = response;
                continue;
            }

            /**
             * 不支持请求中有重复参数 2019-07-11
             */
            /**
             * TODO
             * 1. 数组支持
             * 2. request，response支持
             * 3. @RequestBody支持
             */
            if (param[i].getAnnotations().length == 0) {
                String[] temp = reqParam.get(param[i].getName());
                result[i] = temp == null ? temp : castValue(temp[0], param[i].getType());
            } else if (param[i].isAnnotationPresent(SRequestParam.class)) {
                SRequestParam paramAnnotation = param[i].getAnnotation(SRequestParam.class);
                String[] temp = reqParam.get(paramAnnotation.value().equals("") ? param[i].getName() : paramAnnotation.value());
                result[i] = temp == null ? castValue(paramAnnotation.defaultValue(), param[i].getType()) : castValue(temp[0], param[i].getType());
            } else if (param[i].isAnnotationPresent(SRequestBody.class)) {
                result[i] = JSON.toJavaObject(requestPayload,param[i].getType());
            }
        }
        return result;
    }

    private Object castValue(String value, Class<?> type) {
        if (type.equals(Integer.class)) {
            return Integer.parseInt(value);
        } else if (type.equals(Double.class)) {
            return Double.parseDouble(value);
        } else if (type.equals(Long.class)) {
            return Long.parseLong(value);
        } else if (type.equals(BigDecimal.class)) {
            return new BigDecimal(value);
        }
        return value;
    }

    private String getRequestPayload(HttpServletRequest req) {
        StringBuilder sb = new StringBuilder();
        try (BufferedReader reader = req.getReader();) {
            char[] buff = new char[1024];
            int len;
            while ((len = reader.read(buff)) != -1) {
                sb.append(buff, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return sb.toString();
    }
}
